package com.tbynet.jwp.framework.core;

import java.math.BigInteger;
import java.util.regex.Pattern;

import com.jfinal.core.ActionException;
import com.jfinal.core.Controller;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.render.JsonRender;
import com.jfinal.render.RenderManager;
import com.tbynet.jwp.framework.bean.PageParams;

/**
 * 控制器基类
 *
 * 核心职责：
 * 1. 提供统一的JSON响应格式
 * 2. 客户端类型检测和请求方法判断
 * 3. 分页参数处理和参数验证
 * 4. 安全控制和错误处理
 * 5. 文件上传和会话管理
 *
 * 设计原则：
 * - 不包含业务逻辑，只处理HTTP请求和响应
 * - 统一的参数验证和错误处理
 * - 支持多种客户端检测
 * - 提供安全相关的工具方法
 *
 * @author 佰亿互联
 * @version 3.0
 * @since 2025-11-04
 */
public abstract class JwpController extends Controller {

    /** 日志记录器 */
    protected final Log log = Log.getLog(this.getClass());

    /** 默认分页大小 */
    private static final int DEFAULT_PAGE_SIZE = 20;

    /** 最大分页大小 */
    private static final int MAX_PAGE_SIZE = 100;

    /** 默认文件大小限制（10MB） */
    private static final long DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;

    public BigInteger getParaToBigInteger(String name) {
        return this.toBigInteger(getPara(name), (BigInteger)null);
    }

    public BigInteger getParaToBigInteger(String name, BigInteger defaultValue) {
        return this.toBigInteger(getPara(name), defaultValue);
    }

    public BigInteger[] getParaValuesToBigInteger(String name) {
        String[] values = getParaValues(name);
        if (values != null && values.length != 0) {
            BigInteger[] result = new BigInteger[values.length];

            for(int i = 0; i < result.length; ++i) {
                result[i] = new BigInteger(values[i]);
            }

            return result;
        } else {
            return null;
        }
    }

    private BigInteger toBigInteger(String value, BigInteger defaultValue) {
        try {
            if (StrKit.isBlank(value)) {
                return defaultValue;
            }
            return new BigInteger(value);
        } catch (Exception var4) {
            throw new ActionException(400, RenderManager.me().getRenderFactory().getErrorRender(400), "Can not parse the parameter \"" + value + "\" to Long value.");
        }
    }

    /**
     * XSS过滤的参数获取
     */
    protected String getSafePara(String name) {
        return xssFilter(getPara(name));
    }

    protected String getSafePara(String name, String defaultValue) {
        return xssFilter(getPara(name, defaultValue));
    }

    private String xssFilter(String value) {
        if (StrKit.isBlank(value)) {
            return value;
        }
        // 简单的XSS过滤，可根据需求使用更复杂的库如Jsoup
        return value.replaceAll("<", "&lt;")
                .replaceAll(">", "&gt;")
                .replaceAll("\"", "&quot;")
                .replaceAll("'", "&#x27;")
                .replaceAll("/", "&#x2F;");
    }

    // ========== JSON响应方法 ==========

    /**
     * 成功响应
     *
     * @param ret 返回数据对象
     */
    public void ok(Ret ret) {
        render(new JsonRender(ret.setOk()).forIE());
    }

    /**
     * 失败响应
     *
     * @param ret 返回数据对象
     */
    public void fail(Ret ret) {
        render(new JsonRender(ret.setFail()).forIE());
    }

    /**
     * 失败响应（简化版）
     *
     * @param msg 错误消息
     */
    public void fail(String msg) {
        fail(Ret.by("msg", msg));
    }

    /**
     * 自定义JSON响应
     *
     * @param ret 返回数据对象
     */
    public void json(Ret ret) {
        render(new JsonRender(ret).forIE());
    }

    // ========== 分页参数获取 ==========

    /**
     * 获取分页页码
     *
     * @return 当前页码，默认为1
     */
    protected int getPage() {
        return getInt("page", 1);
    }

    /**
     * 获取分页大小
     *
     * @return 每页大小，默认为20
     */
    protected int getSize() {
        int size = getInt("size", DEFAULT_PAGE_SIZE);
        return Math.min(size, MAX_PAGE_SIZE);
    }

    /**
     * 获取分页参数对象
     *
     * @return 分页参数对象
     */
    protected PageParams getPageParams() {
        int page = getInt("page", PageParams.DEFAULT_PAGE_NUMBER);
        int size = getInt("size", PageParams.DEFAULT_PAGE_SIZE);
        return PageParams.of(page, size);
    }

    /**
     * 获取分页参数对象（自定义默认分页大小）
     *
     * @param defaultPageSize 默认分页大小
     * @return 分页参数对象
     */
    protected PageParams getPageParams(int defaultPageSize) {
        int page = getInt("page", PageParams.DEFAULT_PAGE_NUMBER);
        int size = getInt("size", defaultPageSize);
        return PageParams.of(page, size);
    }

    // ========== 参数验证和错误处理 ==========

    /**
     * 参数错误响应
     *
     * @param field 参数字段名
     * @param msg 错误消息
     */
    protected void paramError(String field, String msg) {
        json(Ret.fail("field", field).set("msg", msg));
    }

    /**
     * 验证必需参数
     *
     * @param field 参数字段
     * @param fieldName 字段显示名称
     * @return 验证是否通过
     */
    protected boolean validateRequired(String field, String fieldName) {
        if (StrKit.isBlank(getPara(field))) {
            paramError(field, fieldName + "不能为空");
            return false;
        }
        return true;
    }

    /**
     * 验证邮箱格式
     *
     * @param email 邮箱地址
     * @param fieldName 字段显示名称
     * @return 验证是否通过
     */
    protected boolean validateEmail(String email, String fieldName) {
        if (StrKit.isBlank(email)) {
            paramError(fieldName, fieldName + "不能为空");
            return false;
        }
        if (!email.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
            paramError(fieldName, fieldName + "格式不正确");
            return false;
        }
        return true;
    }

    /**
     * 验证字符串长度
     *
     * @param str 要验证的字符串
     * @param min 最小长度
     * @param max 最大长度
     * @param fieldName 字段显示名称
     * @return 验证是否通过
     */
    protected boolean validateLength(String str, int min, int max, String fieldName) {
        if (StrKit.isBlank(str)) {
            paramError(fieldName, fieldName + "不能为空");
            return false;
        }
        if (str.length() < min || str.length() > max) {
            paramError(fieldName, fieldName + "长度应在" + min + "-" + max + "个字符之间");
            return false;
        }
        return true;
    }

    /**
     * 验证数字范围
     *
     * @param number 要验证的数字
     * @param min 最小值
     * @param max 最大值
     * @param fieldName 字段显示名称
     * @return 验证是否通过
     */
    protected boolean validateNumberRange(Number number, Number min, Number max, String fieldName) {
        if (number == null) {
            paramError(fieldName, fieldName + "不能为空");
            return false;
        }
        double value = number.doubleValue();
        if (value < min.doubleValue() || value > max.doubleValue()) {
            paramError(fieldName, fieldName + "应在" + min + "-" + max + "之间");
            return false;
        }
        return true;
    }

    // ========== 客户端检测方法 ==========

    /**
     * 获取user agent
     *
     * @return 用户代理字符串
     */
    public String getUserAgent() {
        String userAgent = getHeader("user-agent");
        return userAgent != null ? userAgent.toLowerCase() : "";
    }

    /**
     * 根据user agent获取客户端
     *
     * @param label 客户端标识
     * @return 是否匹配
     */
    public boolean getClient(String label) {
        return Pattern.compile(label + "/([^\\s\\_\\-]+)").matcher(getUserAgent()).find();
    }

    /**
     * 是否微信端
     *
     * @return 是否微信客户端
     */
    public boolean isWeixin() {
        return getClient("micromessenger");
    }

    /**
     * 是否ios端
     *
     * @return 是否iOS客户端
     */
    public boolean isIos() {
        return Pattern.compile("iphone|ipod|ipad|ios").matcher(getUserAgent()).find();
    }

    /**
     * 是否android端
     *
     * @return 是否Android客户端
     */
    public boolean isAndroid() {
        return Pattern.compile("android").matcher(getUserAgent()).find();
    }

    /**
     * 是否移动端
     *
     * @return 是否移动设备
     */
    public boolean isMobile() {
        return isIos() || isAndroid();
    }

    // ========== 请求方法判断 ==========

    /**
     * 是否get请求
     *
     * @return 是否GET请求
     */
    public boolean isGet() {
        return "GET".equalsIgnoreCase(getRequest().getMethod());
    }

    /**
     * 是否post请求
     *
     * @return 是否POST请求
     */
    public boolean isPost() {
        return "POST".equalsIgnoreCase(getRequest().getMethod());
    }

    /**
     * 是否ajax请求
     *
     * @return 是否AJAX请求
     */
    public boolean isAjax() {
        return "XMLHttpRequest".equals(getHeader("X-Requested-With"));
    }

    // ========== 安全相关方法 ==========

    /**
     * 获取真实IP地址
     *
     * @return 真实IP地址
     */
    public String getRealIp() {
        String ip = getHeader("X-Real-IP");
        if (StrKit.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = getHeader("X-Forwarded-For");
        }
        if (StrKit.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = getHeader("Proxy-Client-IP");
        }
        if (StrKit.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = getHeader("WL-Proxy-Client-IP");
        }
        if (StrKit.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = getRequest().getRemoteAddr();
        }

        // 处理X-Forwarded-For多个IP的情况
        if (StrKit.notBlank(ip) && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }

        return ip;
    }

    /**
     * 设置安全Cookie
     *
     * @param name Cookie名称
     * @param value Cookie值
     * @param maxAgeInSeconds 最大生存时间（秒）
     */
    protected void setSecureCookie(String name, String value, int maxAgeInSeconds) {
        setCookie(name, value, maxAgeInSeconds, true);
    }

    /**
     * 删除安全Cookie
     *
     * @param name Cookie名称
     */
    protected void removeSecureCookie(String name) {
        removeCookie(name);
    }

    // ========== 文件上传相关 ==========

    /**
     * 验证文件类型
     *
     * @param fileName 文件名
     * @param allowedTypes 允许的文件类型数组
     * @param fieldName 字段显示名称
     * @return 验证是否通过
     */
    protected boolean validateFileType(String fileName, String[] allowedTypes, String fieldName) {
        if (StrKit.isBlank(fileName)) {
            paramError(fieldName, "请选择文件");
            return false;
        }

        if (allowedTypes == null || allowedTypes.length == 0) {
            log.warn("未设置允许的文件类型");
            return false;
        }

        String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        for (String type : allowedTypes) {
            if (type.equalsIgnoreCase(fileExtension)) {
                return true;
            }
        }

        paramError(fieldName, "不支持的文件类型，请上传" + String.join(",", allowedTypes) + "格式的文件");
        return false;
    }

    /**
     * 验证文件大小
     *
     * @param fileSize 文件大小
     * @param maxSize 最大文件大小
     * @param fieldName 字段显示名称
     * @return 验证是否通过
     */
    protected boolean validateFileSize(long fileSize, long maxSize, String fieldName) {
        if (fileSize > maxSize) {
            paramError(fieldName, "文件大小不能超过" + (maxSize / 1024 / 1024) + "MB");
            return false;
        }
        return true;
    }

    /**
     * 获取默认文件大小限制
     *
     * @return 默认文件大小限制（字节）
     */
    protected long getDefaultMaxFileSize() {
        return DEFAULT_MAX_FILE_SIZE;
    }

    // ========== 会话相关方法 ==========

    /**
     * 获取会话ID
     *
     * @param sessionIdName 会话ID名称
     * @return 会话ID
     */
    protected String getSessionId(String sessionIdName) {
        return getCookie(sessionIdName);
    }

    /**
     * 设置会话ID
     *
     * @param sessionIdName 会话ID名称
     * @param sessionId 会话ID值
     * @param maxAgeInSeconds 最大生存时间（秒）
     */
    protected void setSessionId(String sessionIdName, String sessionId, int maxAgeInSeconds) {
        setSecureCookie(sessionIdName, sessionId, maxAgeInSeconds);
    }

    /**
     * 删除会话ID
     *
     * @param sessionIdName 会话ID名称
     */
    protected void removeSessionId(String sessionIdName) {
        removeSecureCookie(sessionIdName);
    }

    // ========== 响应构建方法 ==========

    /**
     * 构建成功响应
     *
     * @param message 成功消息
     * @param data 返回数据（可选）
     * @return Ret 成功响应对象
     */
    protected Ret buildSuccess(String message, Object data) {
        Ret ret = Ret.ok("msg", message);
        if (data != null) {
            ret.set("data", data);
        }
        return ret;
    }

    /**
     * 构建业务错误响应
     *
     * @param code 业务错误码
     * @param message 错误消息
     * @return Ret 业务错误响应对象
     */
    public Ret buildBusinessError(String code, String message) {
        return Ret.fail("code", code).set("msg", message);
    }

    /**
     * 构建系统错误响应
     *
     * @param message 系统错误消息
     * @return Ret 系统错误响应对象
     */
    public Ret buildSystemError(String message) {
        return Ret.fail("code", "SYSTEM_ERROR").set("msg", message);
    }

    /**
     * 构建参数错误响应
     *
     * @param field 参数字段名
     * @param message 错误消息
     * @return Ret 参数错误响应对象
     */
    public Ret buildParamError(String field, String message) {
        return Ret.fail("code", "PARAM_ERROR").set("field", field).set("msg", message);
    }

}